package com.tongzhan.service;

import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.tongzhan.base.BaseCriteria;
import com.tongzhan.entity.religion.*;
import com.tongzhan.repository.UserRepository;
import com.tongzhan.repository.religion.*;
import com.tongzhan.util.DateUtil;
import com.tongzhan.utils.DateSwitcher;
import com.tongzhan.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
public class ZongjiaoService {

    @Autowired
    private SiteInfoRepository siteInfoRepository;
    @Autowired
    private ReligionRepository religionRepository;
    @Autowired
    private PersonnelRepository personnelRepository;
    @Autowired
    private BillRepository billRepository;
    @Autowired
    private ActivityRepository activityRepository;
    @Autowired
    private InspectionRepository inspectionRepository;
    @Autowired
    private InspectionEvenRepository inspectionEvenRepository;
    @Autowired
    private SiteRepository siteRepository;
    @Autowired
    private InformRepository informRepository;
    @Autowired
    private ConditionRepository conditionRepository;
    @Autowired
    private UsualTaskRepository usualTaskRepository;
    @Autowired
    private LeaveRepository leaveRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private BillTypeRepository billTypeRepository;

    public List<SiteInfoVO> getMapList(Integer type, String date,Integer siteType,String religionCode,String addressName) {
//        if (type == null) {
//            type = 1;
//        }
//        if (siteType == null) {
//            siteType = 0;
//        }
//        if (date == null || "".equals(date)) {
//            date = DateUtil.getSysYear();
//        }
        Query query = new Query();
//        String startDate = DateUtil.getStartDate(type, date);
//        String endDate = DateUtil.getEndDate(type, date);
//        BaseCriteria criteria = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");
        if (!StringUtil.isEmpty(addressName)) {
            query.addCriteria(BaseCriteria.where("streetName").like(addressName));
        }
        query.addCriteria(BaseCriteria.where("ReligionCode").is(religionCode));
        List<SiteInfoVO> siteInfoVOList = new ArrayList<>();
        List<SiteInfo> list = siteInfoRepository.find(query, null);
        list.forEach(c -> {
            SiteInfoVO siteInfoVO = new SiteInfoVO();
            BeanUtils.copyProperties(c, siteInfoVO);
            if (c.getSiteCode()!=null){
                Site info = siteRepository.findOne(Query.query(Criteria.where("SiteCode").is(c.getSiteCode())));
                if (info != null) {
                    siteInfoVO.setLongtitue(info.getX());
                    siteInfoVO.setLatitude(info.getY());
                }
            }
            // 图片有问题
            siteInfoVO.setPicturePath(c.getPicture());
            siteInfoVO.setHistoryEvolution(c.getHistoryEvolution());
            siteInfoVO.setBuildYears(c.getBuildYears());
            siteInfoVO.setSiteCode(c.getSiteCode());
            siteInfoVO.setSiteName(c.getSiteName());
            siteInfoVO.setPersonName(c.getPersonName());
            LocalDateTime createTime = c.getCreateTime();
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String format = dateTimeFormatter.format(createTime);
            siteInfoVO.setCreateTime(format);
            siteInfoVOList.add(siteInfoVO);
        });
        return siteInfoVOList;
    }

    public Map<String, Object> getReligionList(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
//        if (type == null) {
//            type = 1;
//        }
//        if (date == null || "".equals(date)) {
//            date = DateUtil.getSysYear();
//        }
//        List<Map<String,Object>> dateList = new ArrayList<>();
        List<Long> countList = new ArrayList<>();
//        String startDate = DateUtil.getStartDate(type, date);
//        String endDate = DateUtil.getEndDate(type, date);
//        BaseCriteria criteria = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");

        List<Religion> religionList = religionRepository.find(new Query(), null);
        religionList.forEach(c -> {
            String religionCode = c.getReligionCode();
            if ("01".equals(religionCode) || "02".equals(religionCode) || "03".equals(religionCode)
                    || "04".equals(religionCode)) {
                long count = siteInfoRepository.count(new Query(Criteria.where("ReligionCode").is(religionCode)));
//                dateList.add(new HashMap<String,Object>(){{
//                    put("name",c.getReligionName());
//                    put("count",count);
//                }});
                countList.add(count);
                switch (religionCode) {
                    case "01":
                        //佛教
                        map.put("buddhism", count);
                        break;
                    case "02":
                        //道教
                        map.put("taoism", count);
                        break;
                    case "03":
                        //基督教
                        map.put("christianity", count);
                        break;
                    case "04":
                        //民间信仰点
                        map.put("beliefPoint", count);
                        break;
                }
            }
        });
//        long count = siteInfoRepository.count(new Query(Criteria.where("Type").is(1).andOperator(criteria)));
//        dateList.add("民间信仰点");
//        countList.add(count);
        long totalCount = 0;
        for (Long l : countList) {
            totalCount = totalCount + l;
        }
//        map.put("countList", countList);
//        map.put("dataList", dateList);
        map.put("totalCount", totalCount);
        return map;
    }

    public Map<String, Object> getUserInfoList(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
        if (type == null) {
            type = 1;
        }
        if (date == null || "".equals(date)) {
            date = DateUtil.getSysYear();
        }
        List<String> dateList = new ArrayList<>();
        List<Long> countList1 = new ArrayList<>();
        List<Long> countList2 = new ArrayList<>();
        String startDate = DateUtil.getStartDate(type, date);
        String endDate = DateUtil.getEndDate(type, date);
        BaseCriteria criteria = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");

        List<Religion> religionList = religionRepository.find(new Query(), null);
        religionList.forEach(c -> {
            if (!"00".equals(c.getReligionCode())) {
                dateList.add(c.getReligionName());
                long count1 = personnelRepository.count(new Query(Criteria.where("Type").is(1).and("ReligionCode").is(c.getReligionCode()).andOperator(criteria)));
                long count2 = personnelRepository.count(new Query(Criteria.where("Type").is(0).and("ReligionCode").is(c.getReligionCode()).andOperator(criteria)));
                countList1.add(count1);
                countList2.add(count2);
            }
        });
        long totalCount1 = 0;
        for (Long l : countList1) {
            totalCount1 = totalCount1 + l;
        }
        long totalCount2 = 0;
        for (Long l : countList2) {
            totalCount2 = totalCount2 + l;
        }
        map.put("dataList", dateList);
        map.put("countList1", countList1);
        map.put("countList2", countList2);
        map.put("totalCount1", totalCount1);//常驻
        map.put("totalCount2", totalCount2);//暂住
        return map;
    }

    public Map<String, Object> getBillList(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
        if (type == null) {
            type = 1;
        }
        if (date == null || "".equals(date)) {
            date = DateUtil.getSysYear();
        }
        String year = date.substring(0, 4);

        List<Bill> billList = billRepository.find(new Query(Criteria.where("Year").is(year)), null);
        List<BillVO> billVOList = new ArrayList<>();
        List<BigDecimal> revtotalcount = new ArrayList<>();
        List<BigDecimal> outtotalcount = new ArrayList<>();
        List<BigDecimal> revcountList1 = new ArrayList<>();
        List<BigDecimal> revcountList2 = new ArrayList<>();
        List<BigDecimal> revcountList3 = new ArrayList<>();
        List<BigDecimal> revcountList4 = new ArrayList<>();
        List<BigDecimal> outcountList1 = new ArrayList<>();
        List<BigDecimal> outcountList2 = new ArrayList<>();
        List<BigDecimal> outcountList3 = new ArrayList<>();
        List<BigDecimal> outcountList4 = new ArrayList<>();
        billList.forEach(c -> {
            revtotalcount.add(c.getMonthTotalRevenue());
            outtotalcount.add(c.getMonthTotalOutPut());
            if ("01".equals(c.getReligionCode())) {
                revcountList1.add(c.getMonthTotalRevenue());
                outcountList1.add(c.getMonthTotalOutPut());
            } else if ("02".equals(c.getReligionCode())) {
                revcountList2.add(c.getMonthTotalRevenue());
                outcountList2.add(c.getMonthTotalOutPut());
            } else if ("03".equals(c.getReligionCode())) {
                revcountList3.add(c.getMonthTotalRevenue());
                outcountList3.add(c.getMonthTotalOutPut());
            }  else if ("04".equals(c.getReligionCode())) {
                revcountList4.add(c.getMonthTotalRevenue());
                outcountList4.add(c.getMonthTotalOutPut());
            }
        });

        BillVO billVO1 = new BillVO();
        BillVO billVO2 = new BillVO();
        BillVO billVO3 = new BillVO();
        BillVO billVO4 = new BillVO();
        billVO1.setName("佛教");
        BigDecimal rev1 = BigDecimal.valueOf(0);
        for (BigDecimal l : revcountList1) {
            rev1 = rev1.add(l);
        }
        BigDecimal out1 = BigDecimal.valueOf(0);
        for (BigDecimal l : outcountList1) {
            out1 = out1.add(l);
        }
        if (revcountList1 != null && revcountList1.size() > 0) {
            billVO1.setRevdata(rev1);
        } else {
            billVO1.setRevdata(BigDecimal.valueOf(0));
        }
        if (outcountList1 != null && outcountList1.size() > 0) {
            billVO1.setOutdata(out1);
        } else {
            billVO1.setOutdata(BigDecimal.valueOf(0));
        }

        billVO2.setName("道教");

        BigDecimal rev2 = BigDecimal.valueOf(0);
        for (BigDecimal l : revcountList2) {
            rev2 = rev2.add(l);
        }
        BigDecimal out2 = BigDecimal.valueOf(0);
        for (BigDecimal l : outcountList2) {
            out2 = out2.add(l);
        }
        if (revcountList2 != null && revcountList2.size() > 0) {
            billVO2.setRevdata(rev2);
        } else {
            billVO2.setRevdata(BigDecimal.valueOf(0));
        }
        if (outcountList2 != null && outcountList2.size() > 0) {
            billVO2.setOutdata(out2);
        } else {
            billVO2.setOutdata(BigDecimal.valueOf(0));
        }

        billVO3.setName("基督教");

        BigDecimal rev3 = BigDecimal.valueOf(0);
        for (BigDecimal l : revcountList3) {
            rev3 = rev3.add(l);
        }
        BigDecimal out3 = BigDecimal.valueOf(0);
        for (BigDecimal l : outcountList3) {
            out3 = out3.add(l);
        }

        if (revcountList3 != null && revcountList3.size() > 0) {
            billVO3.setRevdata(rev3);
        } else {
            billVO3.setRevdata(BigDecimal.valueOf(0));
        }
        if (outcountList3 != null && outcountList3.size() > 0) {
            billVO3.setOutdata(out3);
        } else {
            billVO3.setOutdata(BigDecimal.valueOf(0));
        }

        billVO4.setName("民间信仰点");

        BigDecimal rev4 = BigDecimal.valueOf(0);
        for (BigDecimal l : revcountList4) {
            rev4 = rev4.add(l);
        }
        BigDecimal out4 = BigDecimal.valueOf(0);
        for (BigDecimal l : outcountList4) {
            out4 = out4.add(l);
        }

        if (revcountList4.size() > 0) {
            billVO4.setRevdata(rev4);
        } else {
            billVO4.setRevdata(BigDecimal.valueOf(0));
        }
        if (outcountList4.size() > 0) {
            billVO4.setOutdata(out4);
        } else {
            billVO4.setOutdata(BigDecimal.valueOf(0));
        }
        billVOList.add(billVO1);
        billVOList.add(billVO2);
        billVOList.add(billVO3);
        billVOList.add(billVO4);
        BigDecimal totalOutCount = BigDecimal.valueOf(0);
        BigDecimal totalRevCount = BigDecimal.valueOf(0);
        for (BigDecimal l : revtotalcount) {
            totalRevCount = totalRevCount.add(l);
        }
        for (BigDecimal l : outtotalcount) {
            totalOutCount = totalOutCount.add(l);
        }
        map.put("billVOList", billVOList);
//        BigDecimal total = totalOutCount.add(totalRevCount);
//        if (total.compareTo(new BigDecimal("0")) == 0) {
//            total = new BigDecimal("1");
//        }
//        BigDecimal rev = totalRevCount.divide(total, 2, RoundingMode.HALF_UP);
//        BigDecimal one = new BigDecimal("1");
//        BigDecimal out = one.subtract(rev);
        map.put("rev", totalRevCount);//收入
        map.put("out", totalOutCount);//支出 单位万
        return map;
    }

    /**
     * 获取财务规范上报次数，活动安全上报次数
     *
     * @return
     */
    public Map<String, Object> getBillActivityCount(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
        if (type == null) {
            type = 1;
        }
        if (date == null || "".equals(date)) {
            date = DateUtil.getSysYear();
        }
        String startDate = DateUtil.getStartDate(type, date);
        String endDate = DateUtil.getEndDate(type, date);
        BaseCriteria criteria1 = DateUtil.getDateSearchCriteria(startDate, endDate, "Time");
        BaseCriteria criteria2 = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");
        // 获取财务总数量
        long billtotal = billRepository.count(new Query().addCriteria(criteria1));
        // 获取活动总数量
        long activitytotal = activityRepository.count(new Query().addCriteria(criteria2));

        map.put("billCount", billtotal);
        map.put("activityCount", activitytotal);

        return map;
    }

    public Map<String, Object> getInspectionList(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
        if (type == null) {
            type = 1;
        }
        if (date == null || "".equals(date)) {
            date = DateUtil.getSysYear();
        }
        String startDate = DateUtil.getStartDate(type, date);
        String endDate = DateUtil.getEndDate(type, date);
        BaseCriteria criteria = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");
        List<InspectionVO> list = new ArrayList<>();
        List<InspectionEven> inspectionEvenList = inspectionEvenRepository.find(new Query(), null);
        inspectionEvenList.forEach(c -> {
            InspectionVO inspectionVO = new InspectionVO();
            inspectionVO.setName(c.getTypeName() + "分析");
            inspectionVO.setRisk(c.getRisk());
            inspectionVO.setIdea(c.getIdea());

//                new Query(Criteria.where("State").is("需整改").and("TypeCode").is(c.getTypeCode()).andOperator(criteria))
//                new Query(Criteria.where("TypeCode").is(c.getTypeCode()).and("State").is("需整改").andOperator(criteria))
            long count = inspectionRepository.count(new Query(Criteria.where("TypeCode").is(c.getTypeCode()).and("State").is("需整改").andOperator(criteria)));
            inspectionVO.setCount(count);
            list.add(inspectionVO);
        });
        map.put("dataList", list);
        return map;

    }

    public Map<String, Object> getSafeList(Integer type, String date) {
        Map<String, Object> map = new HashMap<>();
        if (type == null) {
            type = 1;
        }
        if (date == null || "".equals(date)) {
            date = DateUtil.getSysYear();
        }
        String startDate = DateUtil.getStartDate(type, date);
        String endDate = DateUtil.getEndDate(type, date);
        BaseCriteria criteria = DateUtil.getDateSearchCriteria(startDate, endDate, "CreateTime");

//
//        // 所有总数
//        long total = inspectionRepository.count(new Query(criteria));
//        // 用电安全统计总数
//        long count1 = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("02").andOperator(criteria)));
//        // 消防安全统计总数
//        long count2 = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("03").andOperator(criteria)));
//inspectionList
//        // 用电隐患总数
//        long count3 = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("02").and("State").is("需整改").andOperator(criteria)));
//        // 消防隐患总数
//        long count4 = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("03").and("State").is("需整改").andOperator(criteria)));
//        // 其他安全隐患总数
//        long countOtherSafe = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("01").and("State").is("需整改").andOperator(criteria)));
//
//        BigDecimal totalBig = new BigDecimal(total);
//        BigDecimal count1Big = new BigDecimal(count1);
//        BigDecimal count2Big = new BigDecimal(count2);
//        BigDecimal count3Big = new BigDecimal(count3);
//        BigDecimal count4Big = new BigDecimal(count4);
//        BigDecimal countOtherSafeBig = new BigDecimal(countOtherSafe);
//        // multiply(new BigDecimal(100))
//        BigDecimal electricPre = BigDecimal.ZERO.equals(totalBig) ? BigDecimal.ZERO : count1Big.divide(totalBig, 2, RoundingMode.HALF_UP);
//        BigDecimal firePre = BigDecimal.ZERO.equals(totalBig) ? BigDecimal.ZERO : count2Big.divide(totalBig, 2, RoundingMode.HALF_UP);
//        BigDecimal electricDangerPre = BigDecimal.ZERO.equals(count1Big) ? BigDecimal.ZERO : count3Big.divide(count1Big, 2, RoundingMode.HALF_UP);
//        BigDecimal fireDangerPre = BigDecimal.ZERO.equals(count2Big) ? BigDecimal.ZERO : count4Big.divide(count2Big, 2, RoundingMode.HALF_UP);


        BaseCriteria criteria1 = DateUtil.getDateSearchCriteria(startDate, endDate, "Time");
        // 获取财务总数量
        long billtotal = billRepository.count(new Query().addCriteria(criteria1));
        // 获取活动总数量
        long activitytotal = activityRepository.count(new Query().addCriteria(criteria));

        map.put("billCount", billtotal);
        map.put("activityCount", activitytotal);

        //=== 安全总数统计
        long safeCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("01").andOperator(criteria)));
        long electricCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("02").andOperator(criteria)));
        long fireCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("03").andOperator(criteria)));
        //安全
        map.put("safe", safeCount);
        // 用电
        map.put("electric", electricCount);
        // 消防
        map.put("fire", fireCount);


        //=== 隐患百分比
        // 安全隐患总数
        long safeDangerCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("01").and("State").is("需整改").andOperator(criteria)));
//        BigDecimal safeDangerPre = new BigDecimal(safeDangerCount).divide(new BigDecimal(safeDangerCount), 2, RoundingMode.HALF_UP);
//        BigDecimal safePre = (new BigDecimal(safeCount).subtract(new BigDecimal(safeCount))).divide(new BigDecimal(electricCount), 2, RoundingMode.HALF_UP);
        // 安全隐患百分比
        map.put("safeDangerPre", safeDangerCount);
        // 安全百分比
        map.put("safePre", safeCount - safeDangerCount);
        // 用电隐患总数
        long electricDangerCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("02").and("State").is("需整改").andOperator(criteria)));
//        BigDecimal electricDangerPre = new BigDecimal(electricDangerCount).divide(new BigDecimal(electricCount), 2, RoundingMode.HALF_UP);
//        BigDecimal electricPre = (new BigDecimal(electricCount).subtract(new BigDecimal(electricDangerCount))).divide(new BigDecimal(electricCount), 2, RoundingMode.HALF_UP);
        // 用电隐患百分比
        map.put("electricDangerPre", electricDangerCount);
        // 用电百分比
        map.put("electricPre", electricCount - electricDangerCount);
        // 消防隐患总数
        long fireDangerCount = inspectionRepository.count(new Query(Criteria.where("TypeCode").is("03").and("State").is("需整改").andOperator(criteria)));
//        BigDecimal fireDangerPre = new BigDecimal(fireDangerCount).divide(new BigDecimal(fireCount), 2, RoundingMode.HALF_UP);
//        BigDecimal firePre = (new BigDecimal(fireCount).subtract(new BigDecimal(fireDangerCount))).divide(new BigDecimal(fireCount), 2, RoundingMode.HALF_UP);
        // 消防隐患百分比
        map.put("fireDangerPre", fireDangerCount);
        // 消防百分比
        map.put("firePre", fireCount - fireDangerCount);
        return map;
    }

    public List<TypeVO> getTypeList() {
        return inspectionEvenRepository.findAll().stream().map(c -> {
            TypeVO vo = new TypeVO();
            BeanUtils.copyProperties(c, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    public List<ReligionVO> getReligionTypeList() {
        Query query = new Query();
        List<String> list = Arrays.asList("01", "02", "03", "04");
        query.addCriteria(Criteria.where("ReligionCode").in(list));
        return religionRepository.findAll(query).stream().map(c -> {
            ReligionVO vo = new ReligionVO();
            BeanUtils.copyProperties(c, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    public List<SiteVO> getSiteListByReligionCode(String religionCode, Integer type) {
        Query query = new Query();
        query.addCriteria(Criteria.where("ReligionCode").is(religionCode).and("Jurisdiction").is("是"));
        query.with(Sort.by(Sort.Direction.ASC, "Sort"));
        List<SiteVO> list = new ArrayList<>();
        if (type != null && type == 1) {
            switch (religionCode) {
                case "01":
                    list.add(new SiteVO(){{
                        setSiteCode("佛教团体");
                        setSiteName("佛教团体");
                    }});
                    break;
                case "02":
                    list.add(new SiteVO(){{
                        setSiteCode("道教团体");
                        setSiteName("道教团体");
                    }});
                    break;
                case "03":
                    list.add(new SiteVO(){{
                        setSiteCode("基督教团体");
                        setSiteName("基督教团体");
                    }});
                    break;
                case "04":
                    list.add(new SiteVO(){{
                        setSiteCode("民间信仰点团体");
                        setSiteName("民间信仰点团体");
                    }});
                    break;
            }
        }
        List<SiteVO> voList = siteInfoRepository.findAll(query).stream().map(c -> {
            SiteVO vo = new SiteVO();
            BeanUtils.copyProperties(c, vo);
            return vo;
        }).collect(Collectors.toList());
        list.addAll(voList);
        return list;
    }

    public ConventionalVO conventionalCount() {
        //返回VO
        ConventionalVO vo = new ConventionalVO();
        //政策法规
        long lawCount = informRepository.count(new Query().addCriteria(Criteria.where("IsDeleted").is(0)
                .and("Type").is("Law")));
        vo.setLawCount(lawCount);
        //通知
        long notifyCount = informRepository.count(new Query().addCriteria(Criteria.where("IsDeleted").is(0)
                .and("Type").is("Inform")));
        vo.setNotifyCount(notifyCount);
        //平安报送
        long usualCount = usualTaskRepository.count();
        vo.setUsualCount(usualCount);
        //情况报告
        long conditionCount = conditionRepository.count();
        vo.setConditionCount(conditionCount);
        //活动记录
        long activityCount = activityRepository.count();
        vo.setActivityCount(activityCount);
        return vo;
    }

    public List<LeaveCountVO> leaveCount() {
        List<LeaveCountVO> list = new ArrayList<>();
        //当前时间
        LocalDateTime now = LocalDateTime.now();
        //当年的第一天
        LocalDateTime januaryTime = now.with(TemporalAdjusters.firstDayOfYear());
        for (int i = 0; i <= 11; i++) {
            LocalDateTime time = januaryTime.plusMonths(i);
            List<Leave> leaveList = leaveRepository.findAll(new Query().addCriteria(Criteria.where("Time")
                    .gte(DateSwitcher.getMinTime(time))
                    .andOperator(Criteria.where("Time")
                            .lte(DateSwitcher.getMaxTime(time.with(TemporalAdjusters.lastDayOfMonth()))))));
            LeaveCountVO vo = new LeaveCountVO();
            vo.setMonth(time.getMonthValue());
            vo.setLeaveCount(leaveList.size());
            //销假数量
            int leaveOffCount = 0;
            for (Leave leave : leaveList) {
                if (leave.getCancelState().equals("已销假")) {
                    leaveOffCount++;
                }
            }
            vo.setLeaveOffCount(leaveOffCount);
            list.add(vo);
        }
        return list;
    }

    public InspectionDetailVO getInspectionDetail(String religionCode, String siteCode, String typeCode, Integer status) {
        InspectionDetailVO detailVO = new InspectionDetailVO();
        List<InspectionEven> inspectionEvenList = inspectionEvenRepository.findAll();
        inspectionEvenList.forEach(c -> {
            InspectionVO inspectionVO = new InspectionVO();
            inspectionVO.setName(c.getTypeName() + "分析");
            inspectionVO.setRisk(c.getRisk());
            inspectionVO.setIdea(c.getIdea());
            long count = inspectionRepository.count(new Query(Criteria.where("TypeCode").is(c.getTypeCode())
                    .and("State").is("需整改")));
            inspectionVO.setCount(count);
            switch (c.getTypeCode()) {
                case "01":
                    detailVO.setSafeAnalysis(inspectionVO);
                    break;
                case "02":
                    detailVO.setPowerAnalysis(inspectionVO);
                    break;
                case "03":
                    detailVO.setFireAnalysis(inspectionVO);
                    break;
            }
        });
        //查询条件
        Query query = new Query();
        if (StringUtils.isNotEmpty(religionCode)) {
            query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
        }
        if (StringUtils.isNotEmpty(siteCode)) {
            query.addCriteria(Criteria.where("SiteCode").is(siteCode));
        }
        if (StringUtils.isNotEmpty(typeCode)) {
            query.addCriteria(Criteria.where("TypeCode").is(typeCode));
        }
        if (status != null) {
            if (status == 0) {
                //无问题
                query.addCriteria(Criteria.where("State").is("无问题"));
            } else if (status == 1) {
                //需整改
                query.addCriteria(Criteria.where("State").is("需整改"));
            } else if (status == 2) {
                //已整改
                query.addCriteria(Criteria.where("State").is("已整改"));
            }
        }
        List<InspectionInfoVO> infoVOList = inspectionRepository.findAll(query).stream().map(c -> {
            InspectionInfoVO vo = new InspectionInfoVO();
            BeanUtils.copyProperties(c, vo);
            //图片
            String picture = c.getPicture();
            List<PicVO> picList = new ArrayList<>();
            if (StringUtils.isNotEmpty(picture)) {
                String[] paths = picture.split(",");
                for (String path : paths) {
                    PicVO picVO = new PicVO();
                    picVO.setPath(path);
                    picList.add(picVO);
                }
            }
            vo.setPicList(picList);
            return vo;
        }).collect(Collectors.toList());
        detailVO.setInspectionList(infoVOList);
        return detailVO;
    }

    public PersonnelDetailVO getPersonnelDetail(String religionCode, String siteCode, Integer type) {
        PersonnelDetailVO detailVO = new PersonnelDetailVO();
        //人员总数
        long total = personnelRepository.count();
        detailVO.setTotal(total);
        //性别分析
        SexVO sexVO = new SexVO();
        sexVO.setManCount(personnelRepository.count(new Query()
                .addCriteria(Criteria.where("Sex").is(1))));
        sexVO.setFemaleCount(personnelRepository.count(new Query()
                .addCriteria(Criteria.where("Sex").is(0))));
        detailVO.setSexAnalysis(sexVO);
        //身份分析
        long temporaryStay = personnelRepository.count(new Query().addCriteria(Criteria.where("Type").is(0)));
        List<CountVO> dutiesCount = new ArrayList<>();
        dutiesCount.add(new CountVO(){{
            setName("暂住");
            setCount(temporaryStay);
        }});
        dutiesCount.add(new CountVO(){{
            setName("常驻");
            setCount(total - temporaryStay);
        }});
        detailVO.setDutiesAnalysis(dutiesCount);
        //年龄分析
        List<CountVO> ageCount = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            CountVO vo = new CountVO();
            Query query = new Query();
            int start;
            int end;
            if (i == 1) {
                start = 0;
                end = start + 20;
            } else {
                start = i * 10;
                end = start + 10;
            }
            if (i == 5) {
                query.addCriteria(Criteria.where("Age").gte(start));
                vo.setName(start + "+");
            } else {
                query.addCriteria(Criteria.where("Age").gte(start).andOperator(Criteria.where("Age").lte(end)));
                vo.setName(start + "~" + end);
            }
            long count = personnelRepository.count(query);
            vo.setCount(count);
            ageCount.add(vo);
        }
        detailVO.setAgeAnalysis(ageCount);
        //文化程度分析
        List<String> codeList = Arrays.asList("小学及以下", "初中", "高中", "专科", "本科", "硕士", "博士及以上");
        List<CountVO> eductionCount = new ArrayList<>();
        for (String code : codeList) {
            long count = personnelRepository.count(new Query()
                    .addCriteria(Criteria.where("Education").is(code)));
            CountVO vo = new CountVO();
            vo.setName(code);
            vo.setCount(count);
            eductionCount.add(vo);
        }
        detailVO.setEducationAnalysis(eductionCount);
        //查询条件
        Query query = new Query();
        if (StringUtils.isNotEmpty(religionCode)) {
            query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
        }
        if (StringUtils.isNotEmpty(siteCode)) {
            query.addCriteria(Criteria.where("SiteCode").is(siteCode));
        }
        if (type != null) {
            query.addCriteria(Criteria.where("Type").is(type));
        }
        List<PersonnelInfoVO> infoVOList = personnelRepository.findAll(query).stream().map(c -> {
            PersonnelInfoVO vo = new PersonnelInfoVO();
            BeanUtils.copyProperties(c, vo);
            if (c.getType() == 0) {
                vo.setTypeName("暂住");
            } else {
                vo.setTypeName("常住");
            }
            return vo;
        }).collect(Collectors.toList());
        detailVO.setPersonnelList(infoVOList);
        return detailVO;
    }

    public List<ConventionalDetailVO> getConventionalDetail(Integer type) {
        if (type == 1) {
            //政策法规
            return informRepository.findAll(new Query().addCriteria(Criteria.where("Type").is("Law")))
                    .stream().map(c -> {
                        ConventionalDetailVO vo = new ConventionalDetailVO();
                        BeanUtils.copyProperties(c, vo);
                        return vo;
                    }).collect(Collectors.toList());
        } else if (type == 2) {
            //通知中心
            return informRepository.findAll(new Query().addCriteria(Criteria.where("Type").is("Inform")))
                    .stream().map(c -> {
                        ConventionalDetailVO vo = new ConventionalDetailVO();
                        vo.setTitle(c.getTitle());
                        vo.setTime(vo.getTime());
                        vo.setRealName("民宗科");
                        return vo;
                    }).collect(Collectors.toList());
        } else if (type == 3) {
            //平安报送
            return usualTaskRepository.findAll()
                    .stream().map(c -> {
                        ConventionalDetailVO vo = new ConventionalDetailVO();
                        vo.setTitle(c.getTitle());
                        vo.setTime(c.getCreateTime());
                        vo.setRealName("民宗科");
//                        String usualCode = c.getUsualCode();
//                        if (StringUtils.isNotEmpty(usualCode)) {
//                            //用户名
//                            String username = usualCode.substring(0, usualCode.length() - 14);
//                            //查询用户信息
//                            User user = userRepository.findOne(new Query().addCriteria(Criteria.where("UserName").is(username)));
//                            if (user != null) {
//                                vo.setRealName(user.getRealName());
//                            }
//                        }
                        return vo;
                    }).collect(Collectors.toList());
        } else if (type == 4) {
            //情况报告
            return conditionRepository.findAll()
                    .stream().map(c -> {
                        ConventionalDetailVO vo = new ConventionalDetailVO();
                        BeanUtils.copyProperties(c, vo);
                        vo.setTime(c.getCreateTime());
                        return vo;
                    }).collect(Collectors.toList());
        } else {
            //活动记录
            return activityRepository.findAll()
                    .stream().map(c -> {
                        ConventionalDetailVO vo = new ConventionalDetailVO();
                        BeanUtils.copyProperties(c, vo);
                        vo.setTime(c.getCreateTime());
                        return vo;
                    }).collect(Collectors.toList());
        }
    }

    public SiteDetailVO getSiteDetail(String religionCode) {
        SiteDetailVO detailVO = new SiteDetailVO();
        //场所总数
        long count = siteInfoRepository.count();
//        BigDecimal total = BigDecimal.ZERO;
//        if (count != 0) {
//            total = new BigDecimal(String.valueOf(count));
//        }
        detailVO.setTotal(count);
        //佛教总数
        long buddhismCount = siteInfoRepository.count(new Query()
                .addCriteria(Criteria.where("ReligionCode").is("01")));
//        BigDecimal buddhismTotal = BigDecimal.ZERO;
//        if (buddhismCount != 0) {
//            buddhismTotal = new BigDecimal(String.valueOf(buddhismCount));
//        }
//        detailVO.setBuddhismPer(buddhismTotal.divide(total, 4, RoundingMode.HALF_UP));
        detailVO.setBuddhismPer(buddhismCount);
        //道教总数
        long taoismCount = siteInfoRepository.count(new Query()
                .addCriteria(Criteria.where("ReligionCode").is("02")));
//        BigDecimal taoismTotal = BigDecimal.ZERO;
//        if (taoismCount != 0) {
//            taoismTotal = new BigDecimal(String.valueOf(taoismCount));
//        }
//        detailVO.setTaoismPer(taoismTotal.divide(total, 4, RoundingMode.HALF_UP));
        detailVO.setTaoismPer(taoismCount);
        //基督教总数
        long christianityCount = siteInfoRepository.count(new Query()
                .addCriteria(Criteria.where("ReligionCode").is("03")));
//        BigDecimal christianityTotal = BigDecimal.ZERO;
//        if (christianityCount != 0) {
//            christianityTotal = new BigDecimal(String.valueOf(christianityCount));
//        }
//        detailVO.setChristianityPer(christianityTotal.divide(total, 4, RoundingMode.HALF_UP));
        detailVO.setChristianityPer(christianityCount);
        //民间信仰点总数
        long beliefPointCount = siteInfoRepository.count(new Query()
                .addCriteria(Criteria.where("ReligionCode").is("04")));
//        BigDecimal beliefPointTotal = BigDecimal.ZERO;
//        if (beliefPointCount != 0) {
//            beliefPointTotal = new BigDecimal(String.valueOf(beliefPointCount));
//        }
//        detailVO.setBeliefPointPer(beliefPointTotal.divide(total, 4, RoundingMode.HALF_UP));
        detailVO.setBeliefPointPer(beliefPointCount);
        //查询条件
        Query query = new Query();
        query.with(Sort.by(Sort.Direction.ASC, "ReligionCode", "Sort"));
        if (StringUtils.isNotEmpty(religionCode)) {
            query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
        }
        List<String> siteList = siteInfoRepository.findAll(query).stream().map(SiteInfo::getSiteName).collect(Collectors.toList());
        detailVO.setSiteList(splitList(siteList, 4));
        return detailVO;
    }

    public BillDetailVO getBillDetail(String religionCode, String siteCode, String year, String month) {
        BillDetailVO detailVO = new BillDetailVO();
        //查询条件
        Query query = new Query();
        if (StringUtils.isNotEmpty(religionCode)) {
            query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
        }
        if (StringUtils.isNotEmpty(siteCode)) {
            query.addCriteria(Criteria.where("SiteCode").is(siteCode));
        }
        if (StringUtils.isNotEmpty(year)) {
            query.addCriteria(Criteria.where("Year").is(year));
            if (StringUtils.isNotEmpty(month)) {
                query.addCriteria(Criteria.where("Month").is(month));
            }
        }
        //财务数据列表
        List<BillInfoVO> voList = new ArrayList<>();
        if (StringUtils.isEmpty(siteCode) && StringUtils.isEmpty(religionCode)) {
            //佛教
            voList.add(groupBill(billRepository.findAll(new Query()
                    .addCriteria(Criteria.where("ReligionCode").is("01"))), "佛教团体"));
            //道教
            voList.add(groupBill(billRepository.findAll(new Query()
                    .addCriteria(Criteria.where("ReligionCode").is("02"))), "道教团体"));
            //基督教
            voList.add(groupBill(billRepository.findAll(new Query()
                    .addCriteria(Criteria.where("ReligionCode").is("03"))), "基督教团体"));
            //民间信仰点
            voList.add(groupBill(billRepository.findAll(new Query()
                    .addCriteria(Criteria.where("ReligionCode").is("04"))), "民间信仰点团体"));
        } else if (StringUtils.isEmpty(siteCode) && StringUtils.isNotEmpty(religionCode)) {
            Query search = new Query();
            search.addCriteria(Criteria.where("ReligionCode").is(religionCode));
            BillInfoVO vo = groupBill(billRepository.findAll(search), "");
            switch (religionCode) {
                case "01":
                    vo.setSiteName("佛教团体");
                    break;
                case "02":
                    vo.setSiteName("道教团体");
                    break;
                case "03":
                    vo.setSiteName("基督教团体");
                    break;
                case "04":
                    vo.setSiteName("民间信仰点团体");
                    break;
            }
            voList.add(vo);
        } else {
            Query search = new Query();
            switch (siteCode) {
                case "佛教团体":
                    search.addCriteria(Criteria.where("ReligionCode").is("01"));
                    break;
                case "道教团体":
                    search.addCriteria(Criteria.where("ReligionCode").is("02"));
                    break;
                case "基督教团体":
                    search.addCriteria(Criteria.where("ReligionCode").is("03"));
                    break;
                case "民间信仰点团体":
                    search.addCriteria(Criteria.where("ReligionCode").is("04"));
                    break;
            }
            BillInfoVO infoVO = groupBill(billRepository.findAll(search), siteCode);
            if (infoVO.getSiteName() != null) {
                voList.add(infoVO);
            }
        }
        List<Bill> billList = billRepository.findAll(query);
        List<BillInfoVO> infoVOS = billList.stream().map(c -> {
            BillInfoVO vo = new BillInfoVO();
            BeanUtils.copyProperties(c, vo);
            vo.setTotalInput(c.getMonthTotalRevenue());
            vo.setTotalOutput(c.getMonthTotalOutPut());
            vo.setTotalOver(c.getMonthTotalRevenue().subtract(c.getMonthTotalOutPut()));
            //财务收入类
            List<BillTypeVO> revenueList = JSON.parseArray(c.getRevenueData(), BillTypeVO.class);
            for (BillTypeVO typeVO : revenueList) {
                BillType billType = billTypeRepository.findByPrimaryKey(typeVO.getBillTypeCode());
                typeVO.setBillTypeName(billType.getBillTypeName());
            }
            vo.setRevenueList(revenueList);
            //财务支出类
            List<BillTypeVO> outPutList = JSON.parseArray(c.getOutPutData(), BillTypeVO.class);
            for (BillTypeVO typeVO : outPutList) {
                BillType billType = billTypeRepository.findByPrimaryKey(typeVO.getBillTypeCode());
                typeVO.setBillTypeName(billType.getBillTypeName());
            }
            vo.setOutputList(outPutList);
            return vo;
        }).collect(Collectors.toList());
        voList.addAll(infoVOS);
        detailVO.setBillInfoList(voList);
//        List<Bill> billList = billRepository.findAll(new Query()
//                .addCriteria(Criteria.where("Year").is(String.valueOf(LocalDate.now().getYear()))));
        List<BillCountVO> overCount = new ArrayList<>();
        if (StringUtils.isNotEmpty(month) && StringUtils.isNotEmpty(year)) {
            BillCountVO vo = new BillCountVO();
            vo.setName(month);
            BigDecimal inputValue = BigDecimal.ZERO;
            BigDecimal outputValue = BigDecimal.ZERO;
            for (Bill bill : billList) {
                inputValue = inputValue.add(bill.getMonthTotalRevenue());
                outputValue = outputValue.add(bill.getMonthTotalOutPut());
            }
            vo.setInputValue(inputValue);
            vo.setOutputValue(outputValue);
            vo.setOverValue(inputValue.subtract(outputValue));
            overCount.add(vo);
        } else {
            for (int i = 1; i <= 12; i++) {
                BillCountVO vo = new BillCountVO();
                vo.setName(String.valueOf(i));
                BigDecimal inputValue = BigDecimal.ZERO;
                BigDecimal outputValue = BigDecimal.ZERO;
                for (Bill bill : billList) {
                    if (Integer.parseInt(bill.getMonth()) == i) {
                        inputValue = inputValue.add(bill.getMonthTotalRevenue());
                        outputValue = outputValue.add(bill.getMonthTotalOutPut());
                    }
                }
                vo.setInputValue(inputValue);
                vo.setOutputValue(outputValue);
                vo.setOverValue(inputValue.subtract(outputValue));
                overCount.add(vo);
            }
        }
        detailVO.setOverCount(overCount);
        return detailVO;
    }

    private BillInfoVO groupBill(List<Bill> billList, String siteCode) {
        BillInfoVO vo = new BillInfoVO();
        switch (siteCode) {
            case "佛教团体":
                vo.setSiteName("佛教团体");
                break;
            case "道教团体":
                vo.setSiteName("道教团体");
                break;
            case "基督教团体":
                vo.setSiteName("基督教团体");
                break;
            case "民间信仰点团体":
                vo.setSiteName("民间信仰点团体");
                break;
        }
        BigDecimal totalInput = BigDecimal.ZERO;
        BigDecimal totalOutput = BigDecimal.ZERO;
        for (Bill bill : billList) {
            totalInput = totalInput.add(bill.getMonthTotalRevenue());
            totalOutput = totalOutput.add(bill.getMonthTotalOutPut());
        }
        vo.setTotalInput(totalInput);
        vo.setTotalOutput(totalOutput);
        vo.setTotalOver(totalInput.subtract(totalOutput));
        return vo;
    }

    public List<LeaveDetailVO> getLeaveDetail(String religionCode, String time, Integer state) {
        //查询条件
        Query query = new Query();
        if (StringUtils.isNotEmpty(religionCode)) {
            query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
        }
        if (StringUtils.isNotEmpty(time)) {
            String first = time + "-01";
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            try {
                LocalDateTime start = DateSwitcher.getMinTime(LocalDate.parse(first, dtf).atStartOfDay());
                LocalDateTime end = DateSwitcher.getMaxTime(start.with(TemporalAdjusters.lastDayOfMonth()));
                query.addCriteria(Criteria.where("StartTime").lte(end)
                        .orOperator(Criteria.where("EndTime").gte(start)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (state != null) {
            if (state == 0) {
                query.addCriteria(Criteria.where("CancelState").is("已销假"));
            } else if (state == 1) {
                query.addCriteria(Criteria.where("CancelState").is("未销假"));
            }
        }
        return leaveRepository.findAll(query).stream().map(c -> {
            LeaveDetailVO vo = new LeaveDetailVO();
            BeanUtils.copyProperties(c, vo);
            return vo;
        }).collect(Collectors.toList());
    }
    /**
     * putIfAbsent() 方法是
     *      如果 key对应的value值不存在, key value 添加到 map 中,并返回 null
     *      如果 key对应的value值已存在, key value 不再添加到 map 中, 并返回原 value
     *
     * 故 newKey(这里的newKey对应user对象中的name的值), 如果(newKey, Boolean.TRUE) 在map中已存在,
     * putIfAbsent(newKey, Boolean.TRUE) 会返回 Boolean.TRUE (Boolean.TRUE 被final修饰,故其地址值唯一, 可用作比较)
     * 然后判断是否等于 null, 返回false, filter接收到结果为false的Predicate并将该值过滤掉
     * @param keyExtractor
     * @param <T>
     * @return
     */
    private static <T> Predicate<T> distinctByVariable(Function<? super T, ?> keyExtractor) {
        HashMap<Object, Boolean> map = new HashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 按指定长度分割
     * @param list
     * @param groupSize
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> splitList(List<T> list, int groupSize){
        int length = list.size();
        // 计算可以分成多少组
        int num = ( length + groupSize - 1 )/groupSize ; // TODO
        List<List<T>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = Math.min((i + 1) * groupSize, length);
            newList.add(list.subList(fromIndex,toIndex)) ;
        }
        return newList ;
    }

}